package com.block.common.exception;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.block.common.config.ExceptionNotifyConfig;
import com.block.common.service.LogFactory;
import com.block.common.util.HttpUtil;
import com.block.common.util.LocalDateUtil;

import com.block.common.util.ThreadPoolUtil;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 异常报警通知短信
 */
@Component
public class NotifyExceptionService {


    private ExceptionNotifyConfig exceptionNotifyConfig;

    @Autowired
    public void setExceptionNotifyConfig(ExceptionNotifyConfig exceptionNotifyConfig) {
        this.exceptionNotifyConfig = exceptionNotifyConfig;
    }

    private static Logger logger = LogFactory.getErrorInfoLog();

    private static final String message = "【系统报警通知】【异常处理拦截器】" +
            "【开始时间】%s\n" +
            "【流水号/订单号】%s \n" +
            "【类名】%s,\n" +
            "【方法名】%s,\n" +
            "【参数类型】%s,\n" +
            "【参数值】%s\n " +
            "【异常信息】%s";

    private static final String message_controller =
            "【系统报警通知】controller【异常处理拦截器】" +
            "【开始时间】%s\n" +
            "【流水号/订单号】%s \n" +
            "【URI】%s \n" +
            "【IP】%s \n" +
            "【请求信息】%s\n " +
            "【异常信息】%s";

    private static final String message_notice =
            "【消息通知】{}\n" +
            "【消息类型】{}\n" +
            "【标题】{}\n" +
            "【内容】{}\n" +
            "【异常信息】{}\n";

    /**
     * 异常通知处理类
     *
     * @param flowno
     * @param className
     * @param methodName
     * @param parameterTypes
     * @param arguments
     * @param e
     */
    @Async("asyncExceptionNotify")
    public void notifyException(String flowno, String className, String methodName, Class<?>[] parameterTypes, Object[] arguments, Exception e) {
        String url = exceptionNotifyConfig.getNotifyUrl();
        String excMsg = ExceptionUtil.stacktraceToString(e);

        String parameterType = ToStringBuilder.reflectionToString(parameterTypes);
        String argumentStr = ToStringBuilder.reflectionToString(arguments);
        String errorMsg = String.format(message, LocalDateUtil.getNowDateStr(), flowno, className, methodName, parameterType, argumentStr, excMsg);
        logger.error("------------------start-----{}------{}---------------", LocalDateTime.now(), flowno);
        logger.error(errorMsg);
        logger.error("------------------end-------{}------{}--------------", LocalDateTime.now(), flowno);
        ThreadPoolUtil.excuteMail(() -> sendNotifyInfo(errorMsg,url,exceptionNotifyConfig.getNotifyType()));

    }

    @Async("asyncExceptionNotify")
    public void notifyException(String flowno, String className, String methodName, String argumentStr, Throwable e) {
        String url = exceptionNotifyConfig.getNotifyUrl();
        String excMsg = ExceptionUtil.stacktraceToString(e);

        String errorMsg = String.format(message, LocalDateUtil.getNowDateStr(), flowno, className, methodName, "", argumentStr, excMsg);
        logger.error("------------------start-----{}------{}---------------", LocalDateTime.now(), flowno);
        logger.error(errorMsg);
        logger.error("------------------end-------{}------{}--------------", LocalDateTime.now(), flowno);
         ThreadPoolUtil.excuteMail(() -> sendNotifyInfo(errorMsg,url,exceptionNotifyConfig.getNotifyType()));

    }

    @Async("asyncExceptionNotify")
    public void notifyNoticeInfo(String msgType, String title, String content, Throwable e) {
        String url = exceptionNotifyConfig.getNotifyUrl();
        String excMsg = ObjectUtil.isNotEmpty(e)?ExceptionUtil.stacktraceToString(e):"";

        String errorMsg = StrUtil.format(
                message_notice,
                LocalDateUtil.getNowDateStr(),
                msgType,
                title,
                content,
                excMsg);
        logger.error("------------------start-----{}---------------------", LocalDateTime.now());
        logger.error(errorMsg);
        logger.error("------------------end-------{}--------------------", LocalDateTime.now());
        ThreadPoolUtil.excuteMail(() -> sendNotifyInfo(errorMsg,url,exceptionNotifyConfig.getNotifyType()));
    }

    /**
     * 异常通知处理类
     *
     * @param flowno
     * @param className
     * @param methodName
     * @param parameterTypes
     * @param arguments
     * @param throwable
     */
    @Async("asyncExceptionNotify")
    public void notifyException(String flowno, String className, String methodName, Class<?>[] parameterTypes, Object[] arguments, Throwable throwable) {
        String url = exceptionNotifyConfig.getNotifyUrl();
        String excMsg = ExceptionUtil.stacktraceToString(throwable);

        String parameterType = ToStringBuilder.reflectionToString(parameterTypes);
        String argumentStr = ToStringBuilder.reflectionToString(arguments);
        String errorMsg = String.format(message, LocalDateUtil.getNowDateStr(), flowno, className, methodName, parameterType, argumentStr, excMsg);
        logger.error("------------------start-----{}------{}---------------", LocalDateTime.now(), flowno);
        logger.error(errorMsg);
        logger.error("------------------end-------{}------{}--------------", LocalDateTime.now(), flowno);
        //发送报警通知
        ThreadPoolUtil.excuteMail(() -> sendNotifyInfo(errorMsg,url,exceptionNotifyConfig.getNotifyType()));
    }

    @Async("asyncExceptionNotify")
    public void notifyException(String flowno, String uri, String ip, String reqMsg, Exception e) {
        String url = exceptionNotifyConfig.getNotifyUrl();
        String excMsg = ExceptionUtil.stacktraceToString(e);

        String errorMsg = String.format(message_controller, LocalDateUtil.getNowDateStr(), flowno, uri, ip, reqMsg, excMsg);
        logger.error("--------message_controller----------start-----{}------{}---------------", LocalDateTime.now(), flowno);
        logger.error(errorMsg);
        logger.error("---------message_controller---------end-------{}------{}--------------", LocalDateTime.now(), flowno);
        ThreadPoolUtil.excuteMail(() -> sendNotifyInfo(errorMsg,url,exceptionNotifyConfig.getNotifyType()));
    }

    /**
     * 发送异常通知
     * @param errorMsg
     * @param url
     * @param type
     */
    public void sendNotifyInfo(String errorMsg, String url,String type){
//        if("1".equals(type)){
////            sendTelegram(errorMsg,url);
//        }else{
//            sendDingDing(errorMsg,url);
//        }

        sendDingDing(errorMsg,url);
    }

    public void sendDingDing(String errorMsg, String url) {
        try {
            Map contentMap = new HashMap();
            contentMap.put("content", errorMsg);

            Map param = new HashMap();
            param.put("msgtype", "text");

            param.put("text", contentMap);

            String resultParam = JSONObject.toJSONString(param);

            String result = HttpUtil.doPost(url, resultParam);
            logger.info("发送报警通知返回结果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("发送报警通知返回异常:",e);
        }
    }
    /**
     * 异常信息存入数据库
     *
     * @param bizType
     * @param key
     * @param bizFlowno
     * @param className
     * @param methodName
     * @param e
     * @return
     */
    public boolean saveException(String bizType, String key, String bizFlowno, String className, String methodName, Throwable e) {
        boolean saveResult = false;
        try {
            String excMsg = ExceptionUtil.stacktraceToString(e);

            // TODO: 2022/8/10 异常信息 处理
            
            
        } catch (Exception exception) {
            exception.printStackTrace();
            this.notifyException(key, "ExceptionLogAspect", "saveException", bizType.concat("_").concat(key), exception);
        }
        return saveResult;
    }

}
